home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mntlb20 / lib / scanf.c < prev    next >
C/C++ Source or Header  |  1991-11-16  |  9KB  |  438 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <string.h>
  4.     
  5. /*
  6.  * %efg were loosing big time
  7.  *    fixed  ++jrb
  8.  * all floating conversion now done by atof. much is gained by this.
  9.  *    ++jrb
  10.  */
  11.     
  12. #ifndef __NO_FLOAT__
  13. #define FLOATS 1
  14. #endif
  15.     
  16. #ifndef TRUE
  17. #define TRUE  1
  18. #define FALSE 0
  19. #endif
  20.     
  21. extern        char    _numstr[];
  22.  
  23. #define    skip()    while(isspace(c)) { charcnt++; if ((c=(*get)(ip))<1) goto done; }
  24. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  25.  
  26. #if FLOATS
  27. /* fp scan actions */
  28. #define F_NADA    0    /* just change state */
  29. #define F_SIGN    1    /* set sign */
  30. #define F_ESIGN    2    /* set exponent's sign */
  31. #define F_INT    3    /* adjust integer part */
  32. #define F_FRAC    4    /* adjust fraction part */
  33. #define F_EXP    5    /* adjust exponent part */
  34. #define F_QUIT    6
  35.  
  36. #define NSTATE    8
  37. #define FS_INIT        0    /* initial state */
  38. #define FS_SIGNED    1    /* saw sign */
  39. #define FS_DIGS        2    /* saw digits, no . */
  40. #define FS_DOT        3    /* saw ., no digits */
  41. #define FS_DD        4    /* saw digits and . */
  42. #define FS_E        5    /* saw 'e' */
  43. #define FS_ESIGN    6    /* saw exp's sign */
  44. #define FS_EDIGS    7    /* saw exp's digits */
  45.  
  46. #define FC_DIG        0
  47. #define FC_DOT        1
  48. #define FC_E        2
  49. #define FC_SIGN        3
  50.  
  51. /* given transition,state do what action? */
  52. int fp_do[][NSTATE] = {
  53. {F_INT,F_INT,F_INT,
  54.      F_FRAC,F_FRAC,
  55.      F_EXP,F_EXP,F_EXP},    /* see digit */
  56. {F_NADA,F_NADA,F_NADA,
  57.      F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT},    /* see '.' */
  58. {F_QUIT,F_QUIT,
  59.      F_NADA,F_QUIT,F_NADA,
  60.      F_QUIT,F_QUIT,F_QUIT},    /* see e/E */
  61. {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
  62.      F_ESIGN,F_QUIT,F_QUIT},    /* see sign */
  63. };
  64. /* given transition,state what is new state? */
  65. int fp_ns[][NSTATE] = {
  66. {FS_DIGS,FS_DIGS,FS_DIGS,
  67.      FS_DD,FS_DD,
  68.      FS_EDIGS,FS_EDIGS,FS_EDIGS},    /* see digit */
  69. {FS_DOT,FS_DOT,FS_DD,
  70.  },    /* see '.' */
  71. {0,0,
  72.      FS_E,0,FS_E,
  73.  },    /* see e/E */
  74. {FS_SIGNED,0,0,0,0,
  75.      FS_ESIGN,0,0},    /* see sign */
  76. };
  77. /* which states are valid terminators? */
  78. int fp_sval[NSTATE] = {
  79.     0,0,1,0,1,0,0,1
  80. };
  81. #endif
  82.  
  83. int
  84. _scanf(ip, get, unget, fmt, args)
  85. register unsigned char *ip;
  86. int (*get) __PROTO((unsigned char *));
  87. int (*unget) __PROTO((int, unsigned char *));
  88. register unsigned char *fmt;
  89. char **args;
  90.  
  91. {
  92.     register long n;
  93.     register int c, width, lval, sval, cnt = 0, charcnt = 1;
  94.     int store, neg, base, wide1, endnull, rngflag, c2;
  95.     register unsigned char *p;
  96.     unsigned char delim[128], digits[17], *q;
  97. #if FLOATS
  98.     double fx;
  99.     char fbuf[128], *fbp;
  100.     int fstate, trans;
  101.     extern double atof __PROTO((const char *));
  102. #endif
  103.     
  104.     if (!*fmt)
  105.     return(0);
  106.     
  107.     c = (*get)(ip);
  108.     while(c > 0)
  109.     {
  110.     store = FALSE;
  111.     if (*fmt == '%')
  112.     {
  113.         n    = 0;
  114.         width    = -1;
  115.         wide1    = 1;
  116.         base    = 10;
  117.         lval    = FALSE;
  118.         sval    = FALSE;
  119.         store    = TRUE;
  120.         endnull    = TRUE;
  121.         neg    = -1;
  122.         
  123.         strcpy((char *)delim,  "\011\012\013\014\015 ");
  124.         strcpy((char *)digits, (const char *)_numstr); /* "01234567890ABCDEF" */
  125.         
  126.         if (fmt[1] == '*')
  127.         {
  128.         endnull = store = FALSE;
  129.         ++fmt;
  130.         }
  131.         
  132.         while (isdigit(*++fmt))        /* width digit(s) */
  133.         {
  134.         if (width == -1)
  135.             width = 0;
  136.         wide1 = width = TEN_MUL(width) + (*fmt - '0');
  137.         }
  138.         --fmt;
  139.       fmtnxt:
  140.         ++fmt;
  141.         switch(tolower(*fmt))    /* tolower() is a MACRO! */
  142.         {
  143.           case '*':
  144.         endnull = store = FALSE;
  145.         goto fmtnxt;
  146.         
  147.           case 'l':    /* long data */
  148.         lval = TRUE;
  149.           case 'h':    /* short data (for compatibility) */
  150.         sval = TRUE;
  151.         goto fmtnxt;
  152.         
  153.           case 'i':    /* any-base numeric */
  154.         base = 0;
  155.         goto numfmt;
  156.         
  157.           case 'b':    /* unsigned binary */
  158.         base = 2;
  159.         goto numfmt;
  160.         
  161.           case 'o':    /* unsigned octal */
  162.         base = 8;
  163.         goto numfmt;
  164.         
  165.           case 'x':    /* unsigned hexadecimal */
  166.         base = 16;
  167.         goto numfmt;
  168.         
  169.           case 'd':    /* SIGNED decimal */
  170.         neg = FALSE;
  171.         /* FALL-THRU */
  172.         
  173.           case 'u':    /* unsigned decimal */
  174.           numfmt:                    skip();
  175.         
  176.         if (isupper(*fmt))
  177.             lval = TRUE;
  178.         
  179.         if (!base)
  180.         {
  181.             base = 10;
  182.             neg = FALSE;
  183.             if (c == '%')
  184.             {
  185.             base = 2;
  186.             goto skip1;
  187.             }
  188.             else if (c == '0')
  189.             {
  190.             charcnt++;
  191.             c = (*get)(ip);
  192.             if (c < 1)
  193.                 goto savnum;
  194.             if ((c != 'x')
  195.                 && (c != 'X'))
  196.             {
  197.                 base = 8;
  198.                 digits[8]= '\0';
  199.                 goto zeroin;
  200.             }
  201.             base = 16;
  202.             goto skip1;
  203.             }
  204.         }
  205.         
  206.         if ((neg == FALSE) && (base == 10)
  207.             && ((neg = (c == '-')) || (c == '+')))
  208.         {
  209.           skip1:
  210.             charcnt++;
  211.             c = (*get)(ip);
  212.             if (c < 1)
  213.             goto done;
  214.         }
  215.         
  216.         digits[base] = '\0';
  217.         p = ((unsigned char *)
  218.              strchr((const char *)digits,toupper(c)));
  219.         
  220.         if ((!c || !p) && width)
  221.             goto done;
  222.         
  223.         while (p && width-- && c)
  224.         {
  225.             n = (n * base) + (p - digits);
  226.             charcnt++;
  227.             c = (*get)(ip);
  228.           zeroin:
  229.             p = ((unsigned char *)
  230.              strchr((const char *)digits,toupper(c)));
  231.         }
  232.           savnum:
  233.         if (store)
  234.         {
  235.             p = ((unsigned char *) *args);
  236.             if (neg == TRUE)
  237.             n = -n;
  238.             if (lval)
  239.             *((long*) p) = n;
  240.             else if (sval)
  241.             *((short *) p) = n;
  242.             else
  243.             *((int *) p) = n;
  244.             ++cnt;
  245.         }
  246.         break;
  247.         
  248. #if FLOATS
  249.           case 'e':    /* float */
  250.           case 'f':
  251.           case 'g':
  252.         skip();
  253.         
  254.         if (isupper(*fmt))
  255.             lval = TRUE;
  256.         
  257.         fstate = FS_INIT;
  258.         fbp = fbuf;
  259.         while (c && width--) {
  260.             if (c >= '0' && c <= '9')
  261.             trans = FC_DIG;
  262.             else if (c == '.')
  263.             trans = FC_DOT;
  264.             else if (c == '+' || c == '-')
  265.             trans = FC_SIGN;
  266.             else if (tolower(c) == 'e')
  267.             trans = FC_E;
  268.             else
  269.             goto fdone;
  270.             
  271.             *fbp++ = c;
  272.  
  273.             if (fp_do[trans][fstate] == F_QUIT)
  274.             goto fdone;
  275.             fstate = fp_ns[trans][fstate];
  276.             charcnt++;
  277.             c = (*get)(ip);
  278.         }
  279.         
  280.           fdone:
  281.         *fbp = '\0';
  282.         if (!fp_sval[fstate])
  283.             goto done;
  284.         if (store) {
  285.             fx = (*fbuf == '\0') ? 0.0 : atof(fbuf);
  286.             p = (unsigned char *) *args;
  287.             if (lval)
  288.             *((double *) p) = fx;
  289.             else
  290.             *((float *) p) = (float)fx;
  291.             ++cnt;
  292.         }
  293.         break;
  294. #endif
  295.         
  296.           case 'n':
  297.         if (store) {
  298.           p = (unsigned char *) *args;
  299.           *((int *) p) = charcnt;
  300.         }
  301.         break;
  302.         
  303.           case 'c':    /* character data */
  304.         width = wide1;
  305.         endnull    = FALSE;
  306.         delim[0] = '\0';
  307.         goto strproc;
  308.         
  309.           case '[':    /* string w/ delimiter set */
  310.         
  311.         /* get delimiters */
  312.         p = delim;
  313.         
  314.         if (*++fmt == '^')
  315.             fmt++;
  316.         else
  317.             lval = TRUE;
  318.         
  319.         rngflag = 2;
  320.         if ((*fmt == ']') || (*fmt == '-'))
  321.         {
  322.             *p++ = *fmt++;
  323.             rngflag = FALSE;
  324.         }
  325.         
  326.         while (*fmt != ']')
  327.         {
  328.             if (*fmt == '\0')
  329.             goto done;
  330.             switch (rngflag)
  331.             {
  332.               case TRUE:
  333.             c2 = *(p-2);
  334.             if (c2 <= *fmt)
  335.             {
  336.                 p -= 2;
  337.                 while (c2 < *fmt)
  338.                 *p++ = c2++;
  339.                 rngflag = 2;
  340.                 break;
  341.             }
  342.             /* fall thru intentional */
  343.             
  344.               case FALSE:
  345.             rngflag = (*fmt == '-');
  346.             break;
  347.             
  348.               case 2:
  349.             rngflag = FALSE;
  350.             }
  351.             
  352.             *p++ = *fmt++;
  353.         }
  354.         
  355.         *p = '\0';
  356.         goto strproc;
  357.         
  358.           case 's':    /* string data */
  359.         skip();
  360.           strproc:
  361.         /* process string */
  362.         p = ((unsigned char *) *args);
  363.         
  364.         /* if the 1st char fails, match fails */
  365.         if (width)
  366.         {
  367.             q = ((unsigned char *)
  368.              strchr((const char *)delim, c));
  369.             if((c < 1)
  370.                || (lval ? !q : (int) q))
  371.             {
  372.             if (endnull)
  373.                 *p = '\0';
  374.             goto done;
  375.             }
  376.         }
  377.         
  378.         for (;;) /* FOREVER */
  379.         {
  380.             if (store)
  381.             *p++ = c;
  382.             charcnt++;
  383.             if (((c = (*get)(ip)) < 1) ||
  384.             (--width == 0))
  385.             break;
  386.             q = ((unsigned char *)
  387.              strchr((const char *)delim, c));
  388.             if (lval ? !q : (int) q)
  389.             break;
  390.         }
  391.         
  392.         if (store)
  393.         {
  394.             if (endnull)
  395.             *p = '\0';
  396.             ++cnt;
  397.         }
  398.         break;
  399.         
  400.           case '\0':    /* early EOS */
  401.         --fmt;
  402.         /* FALL THRU */
  403.         
  404.           default:
  405.         goto cmatch;
  406.         }
  407.     }
  408.     else if (isspace(*fmt))        /* skip whitespace */
  409.     {
  410.         skip();
  411.     }
  412.     else 
  413.     {            /* normal match char */
  414.       cmatch:
  415.         if (c != *fmt) 
  416.         break;
  417.         if (fmt[1] == 0) {    /* we're not going to have any more matches */
  418.         return (cnt);
  419.         }
  420.         charcnt++;
  421.         c = (*get)(ip);
  422.     }
  423.     
  424.     if (store)
  425.         args++;
  426.     
  427.     if (!*++fmt)
  428.         break;
  429.     }
  430.     
  431.   done:                        /* end of scan */
  432.     if ((c < 0) && (cnt == 0))
  433.     return(EOF);
  434.     
  435.     (*unget)(c, ip);
  436.     return(cnt);
  437. }
  438.